#include<fstream>
#include<sys/stat.h>
#include<regex>
#include"server.hpp"

#define TIMEOUT_MAX 10  //超时连接销毁  10s

std::unordered_map<int, std::string> _statu_msg = {
    {100, "Continue"},
    {101, "Switching Protocol"},
    {102, "Processing"},
    {103, "Early Hints"},
    {200, "OK"},
    {201, "Created"},
    {202, "Accepted"},
    {203, "Non-Authoritative Information"},
    {204, "No Content"},
    {205, "Reset Content"},
    {206, "Partial Content"},
    {207, "Multi-Status"},
    {208, "Already Reported"},
    {226, "IM Used"},
    {300, "Multiple Choice"},
    {301, "Moved Permanently"},
    {302, "Found"},
    {303, "See Other"},
    {304, "Not Modified"},
    {305, "Use Proxy"},
    {306, "unused"},
    {307, "Temporary Redirect"}, {308, "Permanent Redirect"}, {400, "Bad Request"},
    {401, "Unauthorized"},
    {402, "Payment Required"},
    {403, "Forbidden"}, {404, "Not Found"},
    {405, "Method Not Allowed"},
    {406, "Not Acceptable"},
    {407, "Proxy Authentication Required"},
    {408, "Request Timeout"},
    {409, "Conflict"},
    {410, "Gone"},
    {411, "Length Required"},
    {412, "Precondition Failed"},
    {413, "Payload Too Large"},
    {414, "URI Too Long"},
    {415, "Unsupported Media Type"},
    {416, "Range Not Satisfiable"},
    {417, "Expectation Failed"},
    {418, "I'm a teapot"},
    {421, "Misdirected Request"},
    {422, "Unprocessable Entity"},
    {423, "Locked"},
    {424, "Failed Dependency"},
    {425, "Too Early"},
    {426, "Upgrade Required"},
    {428, "Precondition Required"},
    {429, "Too Many Requests"},
    {431, "Request Header Fields Too Large"},
    {451, "Unavailable For Legal Reasons"},
    {501, "Not Implemented"},
    {502, "Bad Gateway"},
    {503, "Service Unavailable"},
    {504, "Gateway Timeout"},
    {505, "HTTP Version Not Supported"},
    {506, "Variant Also Negotiates"},
    {507, "Insufficient Storage"},
    {508, "Loop Detected"},
    {510, "Not Extended"},
    {511, "Network Authentication Required"}
};
   std::unordered_map<std::string, std::string> _mime_msg = {
    {".aac", "audio/aac"},
    {".abw", "application/x-abiword"}, {".arc", "application/x-freearc"}, {".avi", "video/x-msvideo"},
    {".azw", "application/vnd.amazon.ebook"},
    {".bin", "application/octet-stream"},
    {".bmp", "image/bmp"},
    {".bz", "application/x-bzip"},
    {".bz2", "application/x-bzip2"},
    {".csh", "application/x-csh"},
    {".css", "text/css"}, {".csv", "text/csv"},
    {".doc", "application/msword"},
    {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
    {".eot", "application/vnd.ms-fontobject"},
    {".epub", "application/epub+zip"},
    {".gif", "image/gif"}, {".htm", "text/html"}, {".html", "text/html"},
    {".ico", "image/vnd.microsoft.icon"},
    {".ics", "text/calendar"},
    {".jar", "application/java-archive"},
    {".jpeg", "image/jpeg"}, {".jpg", "image/jpeg"}, {".js", "text/javascript"}, {".json", "application/json"}, {".jsonld", "application/ld+json"}, {".mid", "audio/midi"}, {".midi", "audio/x-midi"}, {".mjs", "text/javascript"}, {".mp3", "audio/mpeg"}, {".mpeg", "video/mpeg"},
    {".mpkg", "application/vnd.apple.installer+xml"},
    {".odp", "application/vnd.oasis.opendocument.presentation"},
    {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
    {".odt", "application/vnd.oasis.opendocument.text"},
    {".oga", "audio/ogg"}, {".ogv", "video/ogg"}, {".ogx", "application/ogg"}, {".otf", "font/otf"}, {".png", "image/png"}, {".pdf", "application/pdf"},
    {".ppt", "application/vnd.ms-powerpoint"},
    {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
    {".rar", "application/x-rar-compressed"},
    {".rtf", "application/rtf"},
    {".sh", "application/x-sh"},
    {".svg", "image/svg+xml"},
    {".swf", "application/x-shockwave-flash"},
    {".tar", "application/x-tar"},
    {".tif", "image/tiff"}, {".tiff", "image/tiff"}, {".ttf", "font/ttf"}, {".txt", "text/plain"},
    {".vsd", "application/vnd.visio"},
    {".wav", "audio/wav"},
    {".weba", "audio/webm"}, {".webm", "video/webm"}, {".webp", "image/webp"}, {".woff", "font/woff"}, {".woff2", "font/woff2"},
    {".xhtml", "application/xhtml+xml"},
    {".xls", "application/vnd.ms-excel"},
    {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
    {".xml", "application/xml"},
    {".xul", "application/vnd.mozilla.xul+xml"},
    {".zip", "application/zip"},
    {".3gp", "video/3gpp"},
    {".3g2", "video/3gpp2"},
    {".7z", "application/x-7z-compressed"}
};

class Util
{
public:
    //将字符串str，按照分隔符sep，分隔成多个字符串，并将其存入vv中
    static void Split(const std::string& str, const std::string sep, std::vector<std::string>& vv)
    {
        int init_pos = 0, offset_pos = 0;

        while (init_pos < str.size())
        {
            offset_pos = str.find(sep, init_pos);//以init_pos为起始点，开始寻找sep的位置
            if (offset_pos == std::string::npos) {
                vv.push_back(str.substr(init_pos));
                break;
            }
            if(offset_pos!=init_pos) //分隔符与分隔符间没有字符串
                vv.push_back(str.substr(init_pos, offset_pos - init_pos));//左闭右开区间
            init_pos = offset_pos + sep.size(); //更新init_pos
        }
    }
    //从file_path中读取数据到str中
    static bool ReadFromFile(const std::string& file_path,std::string& buffer)
    {
        //1.以二进制的方式打开file_path文件
        std::ifstream ifs(file_path.c_str(),std::ios::binary);
        if(ifs.is_open()==false){
            std::cout<<"ifstream open file->"<<file_path.c_str()<<" fail!"<<std::endl;
            return false;
        }
        //2.计算ifs的长度:
        ifs.seekg (0, ifs.end); //跳到ifs文件内数据的末尾
        int length = ifs.tellg();//计算长度
        ifs.seekg (0, ifs.beg); //跳回ifs文件内数据的初始位置
        //3.读取数据到buffer中
        buffer.resize(length);
        ifs.read(&buffer[0],length);
        if(ifs.good()==false){//上次操作出错，即read失败
            std::cout<<"ifstream read file->"<<file_path.c_str()<<" fail!"<<std::endl;
            ifs.close();
            return false;
        }
        //4.关闭文件
        ifs.close();

        return true;
    }
    //将数据写入到file_path文件中
    static bool WriteToFile(const std::string& file_path,std::string data)
    {
        //1.以二进制的方式打开文件，如果文件原先有数据，则直接覆盖
        std::ofstream ofs(file_path.c_str(),std::ios::binary | std::ios::trunc);
        if(ofs.is_open()==false){
            std::cout<<"ofstream open file->"<<file_path.c_str()<<" fail!"<<std::endl;
            return false;
        }
        //2.向文件写入数据
        ofs.write(data.c_str(),data.size());
        if(ofs.good()==false){//上次操作出错，即read失败
            std::cout<<"ifstream read file->"<<file_path.c_str()<<" fail!"<<std::endl;
            ofs.close();
            return false;
        }
        //3.关闭文件
        ofs.close();

        return true;
    }
    //Url编码:Url字符串内的.-_~以及数字和字母不编码，其它字符转换成%HH的形式 空格特殊化处理
    static std::string UrlEncode(const std::string& str,bool turn_space_to_plus=false)
    {
        std::string res;
        for(auto& c:str)
        {   
            if(c=='.' || c=='-' || c=='_' || c=='~' || (c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z'))
                res+=c;
            else if(c==' ' && turn_space_to_plus==true)
                res+='+';
            else
            {
                char buf[4];
                snprintf(buf,4,"%%%02X",c);
                res+=buf;
            }
        }
        return res;
    }
    //响应状态码的描述信息获取
    static std::string StatuDesc(int statu) 
    {
        auto it = _statu_msg.find(statu); 
        if (it != _statu_msg.end())  return it->second;
        
        return "Unknow";
    }
    static std::string ExtMime(const std::string &filename) 
    {
        // a.b.txt 先获取⽂件扩展名
        size_t pos = filename.find_last_of('.'); 
        if (pos == std::string::npos)  return "application/octet-stream"; 
        //根据扩展名，获取mime
        std::string ext = filename.substr(pos); 
        auto it = _mime_msg.find(ext); 
        if (it == _mime_msg.end())  return "application/octet-stream"; 

        return it->second;
    }
    //字符类型转十进制整型
    static int HexToChar(char c)
    {
        if(c>='0' && c<='9')return c-'0';
        if(c>='a' && c<='z')return c-'a'+10;
        if(c>='A' && c<='Z')return c-'A'+10;
        return -1;
    }
    //Url解码：将%HH格式的数据转换成普通ASKII码字符  注意+是否需要特殊化处理
    static std::string UrlDecode(const std::string& str,bool turn_plus_to_space=false)
    {
        std::string res;
        for(int i=0;i<str.size();i++)
        {
            if(str[i]=='+' && turn_plus_to_space==true)
                res+=' ';
            else if(str[i]=='%' && i+2<str.size())
            {
                char ch=HexToChar(str[i+1])*16+HexToChar(str[i+2]);
                res+=ch;
                i+=2;
            }
            else res+=str[i];
        }
        return res;
    }
    //判断一个文件是否是目录文件
    static bool IsDirectory(const std::string& file_path)
    {
        struct stat st;
        int ret=stat(file_path.c_str(),&st);
        if(ret<0){
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    //判断一个文件是否是普通文件
    static bool IsRegularFile(const std::string& file_path)
    {
        struct stat st;
        int ret=stat(file_path.c_str(),&st);
        if(ret<0){
            return false;
        }
        return S_ISREG(st.st_mode);
    }
    //判断资源访问路径的有效性
    static bool IsValid(const std::string& path)
    {
        //按照"/"对path进行分割，计算所访问的路径深度，若深度<0，即超出根目录，则非法
        std::vector<std::string> vv;
        Split(path,"/",vv);
        int level=0;
        for(const auto& str:vv)
        {
            if(str==".."){
                level--;
                if(level<0)return false;//相对路径不能超出根目录，否则非法
            }
            else level++;
        }
        return true;
    }
};

//存储Http请求信息
class HttpRequest
{
public:
    std::string _method;//http协议的请求方法
    std::string _path;  //所访问的资源路径
    std::string _version;//协议版本
    std::string _context;//请求正文
    std::smatch _matches;//资源路径的正则表达式提取
    std::unordered_map<std::string,std::string> _headers; //头部字段
    std::unordered_map<std::string,std::string> _goal_strs; //想要查询的目标字符串
public:
    //重置
    void ReSet()
    {   
        _method.clear();
        _path.clear();
        _version.clear();
        _context.clear();
        _headers.clear();
        _goal_strs.clear();
        std::smatch tmp;
        _matches.swap(tmp);
    }
    //插入头部字段
    void SetHeader(const std::string& key,const std::string& val)
    {
        _headers[key]=val;
    }
    //判断某个头部字段是否存在，并获取
    std::string GetHeader(const std::string& key) 
    {
        return _headers.find(key)==_headers.end()?"":_headers[key];
    }
    //插入目标字符串
    void SetGoalStr(const std::string& key,const std::string& val)
    {
        _goal_strs[key]=val;
    }
    //获取头部字段
    std::string GetGoalStr(const std::string& key)
    {
        return _goal_strs.find(key)==_goal_strs.end()?"":_goal_strs[key];
    }
    //获取正文长度
    size_t GetContentLen() 
    {
        //有一个头部字段叫:Content-Length:1234\r\n
        std::string context_len=GetHeader("Content-Length");
        if(context_len=="")return 0;
        return std::stoi(context_len);

    }
    //判断长短链接
    bool IsLongLink()
    {
        //只有当头部字段里存在Connection，并且Headers[Connection]=="keep-alive"，才是长连接，否则是短连接
        if(GetHeader("Connection")=="keep-alive")return true;
        return false;
    }
};

class HttpResponse
{
public:
    int _status_code;           //响应状态码
    bool _redirect_flag;        //重定向标识
    std::string _echo_context;  //响应正文
    std::string _redirect_url;  //资源路径重定向
    std::unordered_map<std::string,std::string> _headers;//头部字段
public:
    HttpResponse(int status=200):_status_code(status),_redirect_flag(false){}
    void ReSet()
    {
        _status_code=200;
        _redirect_flag=false;
        _echo_context.clear();
        _redirect_url.clear();
        _headers.clear();
    }
    //插入头部字段
    void SetHeader(const std::string& key,const std::string& val)
    {
        _headers[key]=val;
    }
    //判断某个头部字段是否存在，并获取
    std::string GetHeader(const std::string& key)
    {
        return _headers.find(key)==_headers.end()?"":_headers[key];
    }
    //设置正文和type头部字段
    void SetContent(const std::string& echo_context,const std::string& type)
    {
        _echo_context=echo_context;
        SetHeader("Content-Type",type);
    }
    //设置重定向（状态码和url）
    void SetRedirect(int statuscode,const std::string& url)
    {
        _status_code=statuscode;
        _redirect_flag=true;
        _redirect_url=url;
    }
    //判断长短链接
    bool IsLongLink()
    {
        //只有当头部字段里存在Connection，并且Headers[Connection]=="keep-alive"，才是长连接，否则是短连接
        if(GetHeader("Connection")=="keep-alive")return true;
        return false;
    }
};


#define REQUEST_LINE_MAX 8192 //请求行最大长度
typedef enum{ HttpRecvError,HttpRecvLine,HttpRecvHead,HttpRecvBody,HttpRecvOver }HttpRecvStatus;
//协议的上下文处理模块
class HttpContext
{
private:
    int _resp_status;           //响应状态码
    HttpRecvStatus _recv_status;//接收并解析数据的状态（阶段）
    HttpRequest _requestor;     //存储接收信息
private:
    //接收请求行信息
    bool RecvHttpLine(Buffer* buf)
    {
        //从buf中获取一行数据
        std::string str=buf->GetOneLine();
        //接收缓冲区中的请求行不完整，且请求行长度超出最大值 ||  请求行完整，但是请求行的长度超出了最大值
        if((str=="" && buf->EnableReadSize()>=REQUEST_LINE_MAX) || (str.size()>=REQUEST_LINE_MAX)){
            _resp_status=414;//url too long
            _recv_status=HttpRecvError;
            return false;
        }
        //接收缓冲区中的请求行不完整,继续等待
        if(str=="")return true;
        //数据成功取出，更新buf缓冲区
        buf->MoveReadPosition(str.size());
        //请求行接收成功，接下来，解析请求行信息
        return ParseHttpLine(str);
    }
    //解析请求行信息
    bool ParseHttpLine(const std::string& line)
    {
        //Http请求行格式： 请求方法 + 资源路径 + 查询字符串 + 协议版本
        //          例如：  GET /bitejiuyeke/login?user=xiaowang&password=123456789 HTTP/1.1\r\n
        // std::string line="GET /bitejiuyeke/login?user=xiaowang&password=123456789 HTTP/1.1\r\n";
        std::smatch matches;

        //匹配并提取请求方法:GET HEAD POST PUT DELETE 

        std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\r|\r\n)?",std::regex::icase); //.* 匹配除'\r'、'\r\n'外的所有字符串
        //(GET|HEAD|POST|PUT|DELETE) 表示匹配并提取其中任意一个字符串
        //([^?]*)     [^?]表示匹配非?字符  后面的*表示匹配次个或多次
        //\\?(.*)     \\?表示原始的?字符   (.*)表示提取任意字符，直到遇到空格
        //(HTTP/1//.[01])   //.表示原始的.字符   [01]表示匹配0或1
        //(?:\r|\r\n)?    (?:\r|\r\n)表示匹配\r或\r\n，但是不提取   后面的?表示\r|\r\n可以不存在
        //(?:\\?(.*))?    表示?和?后面的字符可能不存在，若存在的话则匹配，并且仅提取?后面的内容，不提取?本身
        //std::regex::icase   表示忽略GET|HEAD|POST|PUT|DELETE的大小写

        bool ret=std::regex_search(line,matches,e);//按照匹配规则e，将从line字符串中提取到的子字符串存放在matches中
        if(ret==false){
            _resp_status=400;//bad request
            _recv_status=HttpRecvError;
            return false;
        }

        _requestor._method=matches[1];
        //将_requestor._method中的字符全部转换成大写
        std::transform(_requestor._method.begin(),_requestor._method.end(),_requestor._method.begin(),::toupper);
        _requestor._path=Util::UrlDecode(matches[2],false);//资源路径中可以存在特殊字符，需要解码  但不需要将+翻译成空格
        _requestor._version=matches[4];
        
        std::vector<std::string> vv;
        Util::Split(matches[3],"&",vv);//将matches[3]按&分割成一个个key=value的子字符串
        for(const auto& str:vv)
        {
            int pos=str.find('=');
            if(pos==std::string::npos){
                _resp_status=400;//bad request
                _recv_status=HttpRecvError;
                return false;
            }
            //将查询字符串以key和value的形式存放在_requestor中, 需要解码，并且需要将+翻译成空格
            _requestor.SetGoalStr(Util::UrlDecode(str.substr(0,pos),true),Util::UrlDecode(str.substr(pos+1),true));
        }
        _recv_status=HttpRecvHead;
        return true;
    }
    //接收头部字段
    bool RecvHttpHead(Buffer* buf)
    {
        if(_recv_status!=HttpRecvHead)return false;
        //一行一行的取出数据，直到遇到空行为止，头部字段格式:key: val\r\nkey: val\r\n
	//std::string str=buf->GetReadPosition();
	//std::cout<<str<<std::endl;
        while(1)
        {
            //从buf中获取一行数据
            std::string str=buf->GetOneLine();
            //数据成功取出，更新buf缓冲区
            buf->MoveReadPosition(str.size());
            //接收缓冲区中的请求行不完整，且请求行长度超出最大值 ||  请求行完整，但是请求行的长度超出了最大值
            if((str.size()==0 && buf->EnableReadSize()>=REQUEST_LINE_MAX) || (str.size()>=REQUEST_LINE_MAX)){
                _resp_status=414;//url too long
                _recv_status=HttpRecvError;
                return false;
            }

            //接收缓冲区中的请求行不完整,继续等待
            if(str.size()==0)return true;
            //直到遇到空行就停止访问
            if(str=="\n" || str=="\r\n")break;
            //一行数据接收成功，接下来，解析本行数据
            
	    if(str.back()=='\n')str.pop_back();
	    if(str.back()=='\r')str.pop_back();
	    bool ret=ParseHttpHead(str);
            if(ret==false)return false;
        }

        //头部处理完毕，进入正文处理阶段
	_recv_status=HttpRecvBody;
        return true;
    }
    //解析头部字段
    bool ParseHttpHead(const std::string line)
    {
        //这一行数据的格式:key: val\r\n
        int pos=line.find(": ");
        if(pos==std::string::npos){
            _resp_status=400;//bad request
            _recv_status=HttpRecvError;
            return false;
        }
        //以key:value的形式插入数据
        _requestor.SetHeader(line.substr(0,pos),line.substr(pos+2));

        return true;
    }
    //处理正文
    bool RecvHttpBody(Buffer* buf)
    {
        if(_recv_status!=HttpRecvBody)return false;
        //1.获取总正文长度
        int context_length=_requestor.GetContentLen();
        //没有正文，则啥都不用处理，直接完成
        if(context_length==0){
            _recv_status=HttpRecvOver;
            return true;
        }
        //2.查看已经取出来的正文长度
        int len=_requestor._context.size();
        //3.计算剩余需要的正文长度
        int need_length=context_length-len;
        //3.1判断buf中的数据长度是否满足所需要的数据长度，若不满足，则全部取出
        if(buf->EnableReadSize()>=need_length){
            _requestor._context+=buf->ReadDataToStringAndPop(need_length);
            _recv_status=HttpRecvOver;
        }
        //3.2 若长度满足，则取出所需长度的数据
        else _requestor._context+=buf->ReadDataToStringAndPop(buf->EnableReadSize());

        return true;
    }
    
public:
    HttpContext():_resp_status(200),_recv_status(HttpRecvLine) {}
    //重置上下文
    void ReSet()
    {
        _resp_status=200;
        _recv_status=HttpRecvLine;
        _requestor.ReSet();
    }
    //获取响应状态码
    int GetRespStatus(){  return _resp_status;  }
    //获取数据的接收状态
    HttpRecvStatus GetRecvStatus(){  return _recv_status;  }
    //获取接收到的数据
    HttpRequest GetRecvInfo(){  return _requestor;  }
    //开始接收并解析数据
    void RecvAndParseInfo(Buffer* buf)
    {
        switch(_recv_status)
        {
            case HttpRecvLine:RecvHttpLine(buf);
            case HttpRecvHead:RecvHttpHead(buf);
            case HttpRecvBody:RecvHttpBody(buf);
            default:break;
        }
    }
};

class HttpServer
{
    using handler=std::function<void(const HttpRequest&,HttpResponse*)>;
private:
    std::vector<std::pair<std::regex,handler>> _get_hash;
    std::vector<std::pair<std::regex,handler>> _post_hash;
    std::vector<std::pair<std::regex,handler>> _put_hash;
    std::vector<std::pair<std::regex,handler>> _delete_hash;
    std::string _static_base_dir;//静态资源根目录
    TcpServer _server; //高并发服务器
private:
    //错误请求的处理
    void HandleErrorRequest(const HttpRequest& req,HttpResponse* resp)
    {
        //1.组织一个错误页面
        std::string echo="<html>";
        echo+="<head>";
        echo+="<meta http-equiv='Content-Type' content='text/html;charset=utf-8>";
        echo+="</head>";
        echo+="<body>";
        echo+="<h1>";
        echo+=std::to_string(resp->_status_code);
        echo+="</h1>";
        echo+="</body>";
        echo+="</html>";
        //2.将页面数据当做响应正文，反馈给客户端
        resp->SetContent(echo,"text/html");
    }
    //将响应结果发送给客户端
    void SendResponseBack(const PtrConnection& conn,HttpRequest& req,HttpResponse* resp)
    {
        //1.先将描述content的属性字段写入resp中
        if(req.IsLongLink()==true)resp->SetHeader("Connection","keep-alive");
        else resp->SetHeader("Connection","close");
        if(resp->_echo_context.size() && resp->GetHeader("Content-Length")=="")
            resp->SetHeader("Content-Length",std::to_string(resp->_echo_context.size()));
        if(resp->_echo_context.size() && resp->GetHeader("Content-Type")=="")
            resp->SetHeader("Content-Type","application/octet-stream");
        if(resp->_redirect_flag==true)
            resp->SetHeader("Location",resp->_redirect_url);
        //2.将resp中的要素，按照http协议格式进行组织
        std::stringstream echo;
        //a.填充响应行
        echo<<req._version<<" "<<std::to_string(resp->_status_code)<<" "<<Util::StatuDesc(resp->_status_code)<<"\r\n";
        //b.填充头部字段
        for(const auto& pir:resp->_headers)
            echo<<pir.first<<": "<<pir.second<<"\r\n";
        
        //d.填充空行（结束标识）
        echo<<"\r\n";
	//c.填充响应正文
        echo<<resp->_echo_context;
        //3.将echo发送给客户端
        conn->Send(echo.str().c_str(),echo.str().size());
    }
    //静态资源请求处理---将所要访问的静态资源文件中的数据读到resp->_echo_context
    void HandleStaticRequest(HttpRequest& req,HttpResponse* resp)
    {
	//BaseDir + /xxx    
	std::string req_path = _static_base_dir + req._path; 
	if (req._path.back() == '/') 
	       	req_path += "index.html";
        
	//将所要访问的静态资源文件中的数据读到resp->_echo_context
        bool ret=Util::ReadFromFile(req._path,resp->_echo_context);
        if(ret==false) {
            resp->_status_code=404;
            return;
        }
	//根据文件后缀，判断文件类型，填充响应报文头部字段 
 	std::string mime = Util::ExtMime(req_path); 
	resp->SetHeader("Content-Type", mime); 
	return;
    }   
    //功能性请求处理
    void HandleFunctionRequest(HttpRequest& req,HttpResponse* resp,std::vector<std::pair<std::regex,handler>> _handle_hash)
    {
        //1.遍历_handle_hash,找到与req._path相匹配的handler,执行handler
        for(const auto& pir:_handle_hash)
            if(std::regex_match(req._path,req._matches,pir.first)==true) 
                return pir.second(req,resp);
        //2.没有与req._path相匹配的handler,则404
	std::cout<<"404"<<std::endl;
        resp->_status_code=404;
    }
    //判断req是否是静态资源请求
    bool is_static_request(HttpRequest& req)
    {
        //1.判断是否设置了静态资源根目录
        if(_static_base_dir.empty()==true)return false;
        //2.判断是否GET || HEAD 请求
        if(req._method!="GET" && req._method!="HEAD")return false;
        //3.判断req._path是否合法
        if(Util::IsValid(req._path)==false)return false;
        //4.判断所访问的文件是否为普通文件  以/结尾的除外，以/结尾的话要在后面加一个index.html
        std::string path=_static_base_dir+req._path;
        if(path.back()=='/')path+="index.html";
        if(Util::IsRegularFile(path)==false)return false;

        //走到这里，说明req要访问的就是静态资源
        req._path=path;
        return true;
    }
    void Route(HttpRequest& req,HttpResponse* resp)
    {
        //如果req是静态资源请求
        if(is_static_request(req)==true)  return HandleStaticRequest(req,resp);
        //req是功能性请求:Get、Head:_get_handler  Post:_post_handler   Put:_put_handler   Delete:_delete_handler
        if(req._method=="GET" || req._method=="HEAD")return HandleFunctionRequest(req,resp,_get_hash);
        if(req._method=="POST")return HandleFunctionRequest(req,resp,_post_hash);
        if(req._method=="PUT")return HandleFunctionRequest(req,resp,_put_hash);
        if(req._method=="DELETE")return HandleFunctionRequest(req,resp,_delete_hash);

        resp->_status_code=405;//Method Not Allowed
    }
    //新链接到来，为新连接创建上下文
    void OnConnection(const PtrConnection& conn)
    {
        conn->SetContext(HttpContext());
        Log(Info,"new connnection coming:%d",conn->GetFd());
    }
    //通过上下文内容，对缓冲区解析+处理
    void OnMessege(const PtrConnection& conn,Buffer* buffer)
    {
        while(buffer->EnableReadSize()>0)
        {
            //1.从conn中获取上下文
            HttpContext* context=conn->GetContext()->GetAddress<HttpContext>();
            //2.通过上下文内容对buffer中的数据进行解析，将其解析成HttpRequest
            context->RecvAndParseInfo(buffer);
            HttpRequest req=context->GetRecvInfo();
            HttpResponse resp(context->GetRespStatus());
            //a.如果解析失败，则无需业务处理，直接返回
            if(context->GetRespStatus()>=400){
                HandleErrorRequest(req,&resp);//处理错误请求
                SendResponseBack(conn,req,&resp);//将响应结果发送给客户端
                context->ReSet();
                buffer->MoveReadPosition(buffer->EnableReadSize());
                conn->Close();//关闭连接
                return;
            }
            
	        //b.如果收到的报文不完整，则先不做处理，等待下次继续接收
            if(context->GetRecvStatus()!=HttpRecvOver) return;
            //3.判断请求类型，然后进行业务处理，并将处理完成后的结果存放在resp中
	        Route(req,&resp);
            //4.安装http格式组织响应，将响应结果发送给客户端
            SendResponseBack(conn,req,&resp);
            //5.重置上下文，走到这里，说明本次数据已经处理完成了，所以需要清空上下文，以免影响下次报文的处理
            context->ReSet();
            //6.判断长短连接
            if(req.IsLongLink()==false)conn->Close();
        }
    }
public:
    HttpServer(int port,int count=3,int timeout=TIMEOUT_MAX):_server(port,count,timeout)
    {
        _server.SetConnEstablishedCalback(std::bind(&HttpServer::OnConnection,this,std::placeholders::_1));
        _server.SetMessegeReceivedCalback(std::bind(&HttpServer::OnMessege,this,std::placeholders::_1,std::placeholders::_2));
    }
    //设置静态资源根目录
    void SetStaticBaseDir(const std::string& path){  _static_base_dir=path;  }
    void SetGetHash(const std::string& key,const handler& val){  _get_hash.push_back(std::make_pair(std::regex(key),val));  }
    void SetPostHash(const std::string& key,const handler& val){  _post_hash.push_back(std::make_pair(std::regex(key),val));  }
    void SetPutHash(const std::string& key,const handler& val){  _put_hash.push_back(std::make_pair(std::regex(key),val));  }
    void SetDeleteHash(const std::string& key,const handler& val){  _delete_hash.push_back(std::make_pair(std::regex(key),val));  }

    void Start(){  _server.Start();  }
};
